home *** CD-ROM | disk | FTP | other *** search
- static char VERSION_STRING[] = "@(#)pcal v4.5 - generate Postscript calendars";
- /*
- * pcal.c - generate PostScript file to print calendar for any month and year
- *
- * The original PostScript code to generate the calendars was written by
- * Patrick Wood (Copyright (c) 1987 by Patrick Wood of Pipeline Associates,
- * Inc.), and authorized for modification and redistribution. The calendar
- * file inclusion code was originally written in "bs(1)" by Bill Vogel of
- * AT&T. Patrick's original PostScript was modified and enhanced several
- * times by King Ables, Tim Tessin, and others whose names have regrettably
- * been lost. This C version was originally created by Ken Keirnan of Pacific
- * Bell; additional enhancements by Joseph P. Larson, Ed Hand, Andrew Rogers,
- * Mark Kantrowitz, Joe Brownlee, Andy Fyfe, Steve Grandi, and Geoff Kuenning.
- * The moon routines were originally written by Jef Poskanzer and Craig
- * Leres, and were incorporated into Pcal by Richard Dyson.
- *
- * Contents:
- *
- * alt_fopen
- * change_color
- * check_numargs
- * color_msg
- * get_args
- * get_flag
- * init_misc
- * main
- * set_color
- * set_debug_flag
- * usage
- *
- * Revision history:
- *
- * 4.5 AWR 11/16/93 support red:green:blue shading value
- * syntax (cf. writefil.c, pcalutil.ps)
- *
- * 11/03/93 widen flag/argument field in usage()
- *
- * 10/01/93 use define_font() and define_shading()
- * (cf. pcalutil.c; latter replaces old
- * gen_shading()) for font and shading
- * redefinition
- *
- * 09/09/93 predefine alternate character set
- * mapping name (cf. writefil.c,
- * fontmaps.ps, pcaldefs.h)
- *
- * 04/28/93 restructure function definitions so
- * function name appears in first column
- * (to facilitate searching for definition
- * by name)
- *
- * 02/05/93 support -# flag (generate multiple
- * copies of each page)
- *
- * 02/11/92 Add support for predefined holidays
- * (cf. pcallang.h, readfile.c)
- *
- * 4.4 AWR 02/10/92 Pipe "help" message through filter
- * defined by environment variable
- * PAGER_ENV (cf. pcaldefs.h)
- *
- * 01/20/92 Add -z flag (extension of change
- * suggested by Steve Grandi)
- *
- * 01/15/92 Add "holiday" to -b, -g; expand -b,
- * -g functionality to -G, -O; allow
- * range of weekday names in all
- *
- * 01/13/92 Support alternate date and title font
- * sizes (single-month calendars only)
- *
- * 01/05/92 Support "{<ordinal>} <day_name> <prep>
- * <date_spec>" (cf. readfile.c)
- *
- * 4.3 AWR 12/06/91 Attempted to simplify some of the
- * mysteries surrounding command-line
- * parsing; moved some processing from
- * get_args() to new check_numargs()
- *
- * 12/05/91 Search for moon file in directory
- * where Pcal lives (cf. moonphas.c)
- *
- * 12/03/91 Add -s flag to override default values
- * for date/fill box shading
- *
- * 11/22/91 Use cvt_escape() (new; cf. pcalutil.c)
- * to convert escape sequences in command
- * line strings
- *
- * 11/18/91 Improve documentation; add init_misc()
- * as catch-all for various initializations
- *
- * 10/25/91 Support moon phases as wildcards
- *
- * 10/17/91 Add -Z flag to generate debugging
- * information; add a pre-pass through
- * command line flags to detect -ZO
- * prior to parsing PCAL_OPTS
- *
- * 10/15/91 Revise logic of date file search
- *
- * 4.2 AWR 10/08/91 Add -k and -K flags to control
- * positioning of small calendars
- *
- * 10/03/91 Add "note{/<n>}" to select box for
- * note text (as per Geoff Kuenning)
- *
- * Add -S flag to suppress generation
- * of the small calendars
- *
- * 10/02/91 Add -N flag to specify alternate
- * heading for notes box
- *
- * Allow user to specify alternate notes
- * font size (-n <name>/<size>)
- *
- * 10/01/91 Add -u flag to generate version info
- * and parameter usage message
- *
- * 09/30/91 Support "if" and "elif" in date file
- *
- * 09/19/91 Add -c flag to generate input file for
- * Un*x "calendar" utility
- *
- * 4.11 AWR 08/20/91 Add support for "nearest" keyword
- * (as per Andy Fyfe)
- *
- * define "whole_year" when -w set
- *
- * 08/21/91 Support %u, %w, %D, %M format specs
- * and optional number following %[+-]
- * (cf. writefil.c)
- *
- * 4.1 AWR 08/16/91 Add -G flag to print "gray" dates as
- * outlined, gray-filled characters
- *
- * Fix potential bug in julday() (cf.
- * moonphas.c)
- *
- * 4.02 AWR 07/02/91 Add -v flag to print version info only;
- * call find_executable() to get true
- * program pathname (cf. pcalutil.c);
- * add format specifiers to text strings
- * (cf. writefil.c)
- *
- * 4.01 AWR 03/19/91 Incorporate revised moonphas.c (q.v.)
- *
- * 4.0 AWR 02/24/91 Add alt_fopen() to search for file
- * in alternate path; use to look for
- * date file in same directory as
- * Pcal executable (as per Floyd Miller)
- *
- * Support negative ordinals (cf.
- * readfile.c, pcalutil.c)
- *
- * Support expressions in preprocessor
- * "if{n}def" lines (cf. exprpars.c)
- *
- * Support "even", "odd" ordinals (cf.
- * readfile.c) and ordinals > 5th
- *
- * Support -B (leave unused boxes blank)
- * flag
- *
- * Separated into moonphas.c, pcal.c,
- * pcalutil.c, readfile.c, and writefil.c;
- * added support for moon phase file
- *
- * Support -w (whole year) flag; fix
- * various bugs and nonportable constructs
- *
- *
- * Parameters:
- *
- * pcal [opts] generate calendar for current month/year
- * (current year if -w flag specified)
- *
- * pcal [opts] yy generate calendar for entire year yy
- *
- * pcal [opts] mm yy generate calendar for month mm
- * (Jan = 1), year yy (19yy if yy < 100)
- * (12 months starting with mm/yy if -w
- * specified)
- *
- * pcal [opts] mm yy n as above, for n consecutive months (n
- * rounded to next multiple of 12 if -w
- * specified)
- *
- * Output:
- *
- * PostScript file to print calendars for all selected months.
- *
- * Options:
- *
- * -I initialize all parameters to program defaults
- *
- * -b <DAY> print specified weekday in black
- * -g <DAY> print specified weekday in gray
- * -O <DAY> print specified weekday as unfilled outlines
- * -G <DAY> print specified weekday as filled outlines
- * (default: print Saturdays and Sundays in gray)
- *
- * -s {<DATE>}{/<FILL>}
- * specify alternate shading values for dates
- * and fill boxes
- * (default: dates = 0.8, fill boxes = 0.9)
- *
- * -d <FONT>{/<SIZE>}
- * specify alternate font/size for dates
- * (default: Times-Bold/25)
- *
- * -n <FONT>{/<SIZE>}
- * specify alternate font/size for notes in boxes
- * (default: Helvetica-Narrow/6)
- *
- * -t <FONT>{/<SIZE>}
- * specify alternate font for text headings (and
- * font size for month/year title)
- * (default: Times-Bold/48)
- *
- * -D <SYM> define preprocessor symbol
- * -U <SYM> un-define preprocessor symbol
- *
- * -e generate empty calendar (ignore date file)
- *
- * -f <FILE> specify alternate date file (default:
- * ~/.calendar on Un*x, SYS$LOGIN:CALENDAR.DAT
- * on VMS, s:calendar.dat on Amiga; if
- * environment variable [logical name on VMS]
- * PCAL_DIR exists, looks there instead; if
- * not found in either place, looks in same
- * directory as Pcal executable)
- *
- * -o <FILE> specify alternate output file (default:
- * stdout on Un*x, CALENDAR.PS on VMS,
- * RAM:calendar.ps on Amiga)
- *
- * -L <STRING> specify left foot string (default: "")
- * -C <STRING> specify center foot string (default: "")
- * -R <STRING> specify right foot string (default: "")
- *
- * -N <STRING> specify notes box header (default: "Notes")
- *
- * -l generate landscape-mode calendars
- * -p generate portrait-mode calendars
- * (default: landscape-mode)
- *
- * -h (command line only) write version information
- * and full help message to stdout
- * -u (command line only) write version information
- * and parameter usage message to stdout
- * -v (command line only) write version information
- * alone to stdout
- *
- * -m draw a small moon icon on the days of the
- * full, new, and half moons.
- * -M draw a small moon icon every day.
- * (default: no moons)
- *
- * -F <DAY> select alternate day to be displayed as the
- * first day of the week (default: Sunday)
- *
- * -A dates are in American format (e.g., 10/15/90,
- * Oct 15) (default)
- * -E dates are in European format (e.g., 15.10.90,
- * 15 Oct)
- *
- * -x <XSCALE> These two options can be used to change
- * -y <YSCALE> the size of the calendar.
- *
- * -X <XTRANS> These two options can be used to relocate
- * -Y <YTRANS> the position of the calendar on the page.
- *
- * -j print Julian dates (day of year)
- * -J print Julian dates and days remaining
- * (default: neither)
- *
- * -w print whole year (12 months) per page
- *
- * -c generate input for Un*x calendar(1) utility
- *
- * -z <VALUE> specify alternate time zone for moon phase
- * calculation algorithm
- *
- * -B leave unused calendar boxes blank
- *
- *
- * There are many ways to specify these options in addition to using the
- * command line; this facilitates customization to the user's needs.
- *
- * If the environment variable (global symbol on VMS) PCAL_OPTS is
- * present, its value will be parsed as if it were a command line.
- * Any options specified will override the program defaults.
- *
- * All options but -[cefhuvDU] may be specified in the date file by
- * including one or more lines of the form "opt <options>". Any such
- * options override any previous values set either as program defaults,
- * via PCAL_OPTS, or in previous "opt" lines.
- *
- * Options explicitly specified on the command line in turn override all
- * of the above.
- *
- * Any flag which normally takes an argument may also be specified without
- * an argument; this resets the corresponding option to its default. -D
- * alone un-defines all symbols; -U alone has no effect.
- *
- * Parameters and flags may be mixed on the command line. In some cases
- * (e.g., when a parameter follows a flag without its optional argument)
- * this may lead to ambiguity; the dummy flag '-' (or '--') may be used
- * to separate them, i.e. "pcal -t - 9 90".
- *
- *
- * Date file syntax:
- *
- * 1) Basic Syntax:
- *
- * The following rules describe the syntax of date file entries:
- *
- * year <year>
- *
- * opt <options>
- *
- * note{/<number>} <month_spec> <text>
- * note{/<number>} <month> <text>
- *
- * if -A flag (American date formats) specified:
- * <month_name> <day>{*} {<text>}
- * <month><sep><day>{<sep><year>}{*} {<text>}
- *
- * if -E flag (European date formats) specified:
- * <day>{<sep>} <month_name>{*} {<text>}
- * <day>{<sep>} <month>{<sep>}{*} {<text>}
- * <day><sep><month>{<sep><year>}{*} {<text>}
- *
- * <ordinal> <day_name> in <month_spec>{*} {<text>}
- * {<ordinal>} <day_name> <prep> <date_spec>
- *
- * <holiday>
- *
- * where
- *
- * {x} means x is optional
- *
- * <date_spec> := any of the above date specs (not year, note, or opt)
- * <month_name> := first 3+ characters of name of month, or "all"
- * <month_spec> := <month_name>, or "year"
- * <day_name> := first 3+ characters of name of weekday, "day",
- * "weekday", "workday", "holiday", "nonweekday",
- * "nonworkday", "nonholiday", "new_moon",
- * "first_quarter", "full_moon", or "last_quarter"
- * <ordinal> := ordinal number ("1st", "2nd", etc.), "first" .. "fifth",
- * "last", "even", "odd", or "all"
- * <prep> := "before", "preceding", "after", "following", "nearest",
- * "on_or_before", or "on_or_after"
- * <holiday> := "Christmas", "Thanksgiving", etc.
- *
- * <sep> := one or more non-numeric, non-space, non-'*' characters
- * <month>, <day>, <year> are the numeric forms
- *
- * <options> := any command-line option except -[cefhuvDU]
- *
- * Comments start with '#' (unless escaped by '\') and run through
- * end-of-line.
- *
- * Holidays may be flagged by specifying '*' as the last character of the
- * date field(s), e.g. "10/12* Columbus Day", "July 4* Independence
- * Day", etc. Any dates flagged as holidays will be printed in gray, and
- * any associated text will appear adjacent to the date.
- *
- * Note that the numeric date formats (mm/dd{/yy}, dd.mm{.yy}) support an
- * optional year, which will become the subsequent default year. The
- * alphabetic date formats (month dd, dd month) do not support a year
- * field; the "year yy" command is provided to reset the default year.
- *
- * European dates may also be specified as "dd. mm." and "dd. month" if
- * desired.
- *
- * "Floating" days may be specified in the date file as "first Mon in
- * Sep", "last Mon in May", "4th Thu in Nov", etc.; any word may be used
- * in place of "in". "Relative floating" days (e.g. "Fri after 4th Thu
- * in Nov") are also accepted; they may span month/year bounds. Pcal
- * also accepts date specs such as "all Friday{s} in October", "last
- * Thursday in all", etc., and produces the expected results; "each" and
- * "every" are accepted as synonyms for "all". Negative ordinals are
- * allowed; "-2nd" means "next to last".
- *
- * "Floating" days may also be specified relative to a fixed date:
- * "fourth Sunday before 12/25", etc; note, however, that only positive
- * ordinals are meaningful in this context.
- *
- * The words "day", "weekday", "workday", and "holiday" may be used as
- * wildcards: "day" matches any day, "weekday" matches any day normally
- * printed in black, "workday" matches any day normally printed in black
- * and not explicitly flagged as a holiday, and "holiday" matches any day
- * explicitly flagged as a holiday. "Nonweekday", "nonworkday", and
- * "nonholiday" are also supported and have the obvious meanings. Moon
- * phases may also appear as wildcards; "nm" is accepted as a synonym for
- * "new_moon", "1q" and "fq" for "first_quarter", "fm" for "full_moon",
- * and "3q", "lq", and "third_quarter" for "last_quarter".
- *
- * "Odd" and "even" do not refer to the actual date; instead, "odd" means
- * "alternate, starting with the first"; "even" means "alternate,
- * starting with the second". Thus, "odd Fridays in March" refers to the
- * first, third, and (if present) fifth Fridays in March - not to those
- * Fridays falling on odd dates.
- *
- * "All" refers to each individual month; "year" refers to the year as an
- * entity. Thus "odd Fridays in all" refers to the first/third/ fifth
- * Friday of each month, while "odd Fridays in year" refers to the first
- * Friday of January and every other Friday thereafter.
- *
- * Additional notes may be propagated to an empty calendar box by the
- * inclusion of one or more lines of the form "note{/<number>} <month>
- * <text>", where <month> may be numeric or alphabetic; "note{/<number>}
- * all <text>" propagates <text> to each month in the current year.
- * <number> is an optional positive or negative number specifying the
- * empty box where the associated text is to be placed: if positive,
- * Pcal counts forward from the first empty box; if negative, Pcal counts
- * backward from the last empty box. Thus, "note/1 ..." places the
- * associated text in the first empty box, and "note/-3 ..." in the
- * third-to-last; the default is -1 (last empty box). (Note that if the
- * -S option is used, it must be specified either on the command line or
- * prior to any "note" lines in the date file.)
- *
- *
- * 2) Format specifiers:
- *
- * Pcal also allows format specifiers in the text (and foot strings - cf.
- * the -L, -C, -R, and -N options); each will be replaced by its
- * equivalent string as outlined in the table below. (Most of these are
- * derived from the strftime() function; %[lnouwMD0+-] are Pcal-specific.)
- *
- * %a : abbreviated weekday
- * %A : full weekday
- * %b : abbreviated month name
- * %B : full month name
- * %d : day of month (1-31)
- * %j : day of year (1-366)
- * %l : days left in year (0-365)
- * %m : month (1-12)
- * %u : week number (1-54)
- * %U : week number (0-53)
- * %w : week number (1-54)
- * %W : week number (0-53)
- * %y : year w/o century (00-99)
- * %Y : year w/century
- * %% : '%' character
- *
- * %o : print number as ordinal
- * %0 : print number with leading zeroes
- * %+ : use following month or year
- * %- : use previous month or year
- * %{+N}[DWMY] : adjust date by +N days/weeks/months/years
- * %{-N}[DWMY] : adjust date by -N days/weeks/months/years
- *
- * %u considers the week containing 1/1 as week 1 and the following
- * logical Sunday (the first day of the week as printed; cf. the -F
- * flag) as the start of week 2; %U considers the first logical Sunday as
- * the first day of week 1. %w and %W behave like %u and %U
- * respectively, but use the first logical Monday instead. (Note that %w
- * has a different meaning to strftime().)
- *
- * %o prints a number as an ordinal, with the appropriate suffix ("st",
- * "nd", "rd", or "th" in English) appended; for example, "%od" prints
- * the day of the month as "1st", "2nd", "3rd", etc.
- *
- * Unlike strftime(), Pcal's default is to print numbers (except %y)
- * without leading zeroes. If leading zeroes are desired, the '0' prefix
- * may be used; for example, "%0j" prints the day of year as 001-365.
- *
- * %+ and %- direct Pcal to substitute the following/previous month/year
- * in the following [bBmyY] specifier; for example, "%+B" prints the name
- * of the next month.
- *
- * %{[+-]N}[DWMY] do not print anything, but instead adjust the working
- * date by +-N days (D), weeks (W), months (M), or years (Y); subsequent
- * format specifiers use the adjusted date instead of the current date.
- * For example, "%+1M %B %Y" adjusts the date forward by one month and
- * then prints the resulting month and year ("January 1991" in December,
- * 1990); "%-2W %b %d" adjusts the date backward by two weeks and prints
- * the resulting month and day ("Jul 26" on August 9).
- *
- * Such date adjustments are normally cumulative; for example, "%+1Y%-1D"
- * adjusts the date forward by one year and then backward by one day. If
- * %D or %M is specified alone (or if N is zero), Pcal restores the
- * original date. (Note that %M has a different meaning to strftime().)
- *
- * The "Notes" box uses the first of the current month as the default
- * date. All foot strings use the first of the current month in single-
- * month mode and the first of the starting month in whole-year mode.
- *
- *
- * 3) Preprocessing:
- *
- * Simple cpp-like functionality is provided. The date file may include
- * the following commands, which work like their cpp counterparts:
- *
- * define <sym>
- * undef <sym>
- *
- * if{{n}def} <expr>
- * ...
- * { elif <expr>
- * ... }*
- * { else
- * ... }
- * endif
- *
- * include{?} <file>
- *
- * Note that these do not start with '#', which is reserved as a comment
- * character.
- *
- * <sym> is a symbol name consisting of a letter followed by zero or more
- * letters, digits, or underscores ('_'). Symbol names are always
- * treated in a case-insensitive manner.
- *
- * <expr> is an expression consisting of symbol names joined by the
- * logical operators (in order of precedence, high to low) '!' (unary
- * negate), '&' (and), '^' (exclusive or), and '|' (inclusive or). '&&'
- * and '||' are accepted as synonyms for '&' and '|' respectively; the
- * order of evaluation may be altered by the use of parentheses. A
- * symbol whose name is currently defined evaluates to TRUE; one whose
- * name is not currently defined evaluates to FALSE. Thus "ifdef A | B |
- * C" is TRUE if any of the symbols A, B, and C is currently defined, and
- * "ifdef A & B & C" is TRUE if all of them are.
- *
- * "ifndef A | B | C" is equivalent to "ifdef !(A | B | C)" (or, using
- * DeMorgan's Law, "ifdef !A & !B & !C") - in other words, TRUE if none
- * of the symbols A, B, and C is currently defined.
- *
- * "if" is accepted as a synonym for "ifdef".
- *
- * "elif A" is TRUE if A is defined. Multiple "elif" clauses may appear;
- * at most one "if{{n}def}", "elif", or "else" clause in a given block
- * will be processed.
- *
- * "define" alone deletes all the current definitions; "if{def}" alone is
- * always false; "ifndef" alone is always true.
- *
- * The file name in the "include" directive may optionally be surrounded
- * by "" or <>; in any case, path names are taken to be relative to the
- * location of the file containing the "include" directive. If the
- * string "%y" appears in the file name, it is replaced by the last two
- * digits of the current year. The alternate form, "include?", directs
- * pcal to silently continue if the specified file cannot be opened.
- *
- *
- * 4) Miscellaneous:
- *
- * The "-w" flag defines the symbol "whole_year", which may be tested in
- * the same manner as any user-defined symbol.
- *
- * Pcal also supports several predefined holidays; type "pcal -h" to
- * generate a list of these.
- *
- */
-
- /*
- * Standard headers:
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <string.h>
-
- /*
- * Pcal-specific definitions:
- */
-
- #define MAIN_MODULE 1
- #include "pcaldefs.h"
- #include "pcalglob.h"
- #include "pcallang.h"
-
- /*
- * Globals:
- */
-
- static int nargs = 0; /* count of non-flag args */
- static int numargs[MAXARGS]; /* non-flag (numeric) args */
- static int init_month, init_year, nmonths; /* parsed values of above */
-
-
- /*
- * Main program - parse and validate command-line arguments, open files,
- * generate PostScript boilerplate and code to generate calendars.
- *
- * Program structure:
- *
- * For maximum user flexibility, Pcal gives the user several different ways
- * to set program flags and/or override earlier choices. This necessitates
- * that main() call get_args() (directly or indirectly) several times:
- *
- * a) to parse the command line, looking only for -Z flags (which turn on
- * debugging information) and numeric parameters
- *
- * b) to parse environment variable (global symbol on VMS) PCAL_OPTS, if
- * defined
- *
- * c) to parse the command line a second time, looking for options
- * related to finding/interpreting the date file: -[cefhuvDU]
- *
- * d) main() calls read_datefile() to read and parse the date file; it
- * in turn calls get_args() once per "opt" line in the date file
- *
- * e) to parse the command line one final time, allowing the user to
- * override any flags other than those listed in c) above
- *
- * The rest of it is straightforward: main() attempts to open the output file
- * (if any), and, if successful, calls write_psfile() to generate the
- * PostScript output (or write_calfile() to generate the "calendar" input).
- * Some minor housekeeping and we're done.
- *
- */
- int
- #ifdef PROTOS
- main(int argc,
- char **argv)
- #else
- main(argc, argv)
- int argc;
- char **argv;
- #endif
- {
- FILE *dfp = NULL; /* date file pointer */
- char *p, *pathlist[10];
- char tmp[STRSIZ];
- int n;
-
- init_misc(); /* handle initialization warts */
-
- /* extract root program name and program path - note that some
- * systems supply the full pathname and others just the root
- */
-
- strcpy(progname, **argv ? *argv : "pcal");
-
- if ((p = strrchr(progname, END_PATH)) != NULL)
- strcpy(progname, ++p);
- #ifndef UN_X
- if ((p = strchr(progname, '.')) != NULL)
- *p = '\0'; /* strip suffix if non-Un*x */
- #endif
-
- mk_path(progpath, find_executable(*argv));
-
- /* get version from VERSION_STRING (for use in PostScript comment) */
- strcpy(tmp, VERSION_STRING + 4);
- p = strchr(tmp, ' ') + 1; /* skip program name */
- *strchr(p, ' ') = '\0'; /* terminate after version */
- strcpy(version, p);
-
- /*
- * Get the arguments from a) the command line (pre-pass to pick up
- * debug flags only), b) the environment variable PCAL_OPTS, c) the
- * first command line pass, d) "opt" lines in the date file, and e)
- * a final command line pass, in that order
- */
-
- /* make an preliminary pass to look for the debug flags (to ensure
- * ensure that -ZO will print any flags set in PCAL_OPTS); also
- * get and validate the numeric command-line arguments
- */
- if (!get_args(argv, P_CMD0, NULL, TRUE)) {
- usage(stderr, FALSE); /* invalid flag or param */
- exit(EXIT_FAILURE);
- }
-
- /* parse environment variable PCAL_OPTS as a command line */
-
- if ((p = getenv(PCAL_OPTS)) != NULL) {
- strcpy(lbuf, "pcal "); /* dummy program name */
- strcat(lbuf, p);
- (void) loadwords(words, lbuf); /* split string into words */
- if (! get_args(words, P_ENV, PCAL_OPTS, FALSE)) {
- usage(stderr, FALSE);
- exit(EXIT_FAILURE);
- }
- }
-
- /* parse command-line arguments once to find name of date file, etc. */
-
- (void) get_args(argv, P_CMD1, NULL, FALSE);
-
- /* Attempt to open the date file as specified by the [-e | -f] flags */
-
- switch (datefile_type) {
- case NO_DATEFILE:
- dfp = NULL;
- break;
-
- case USER_DATEFILE:
- /* Attempt to open user-specified calendar file: search
- * first in the current directory, then in PCAL_DIR (if
- * defined), and finally in the directory where the Pcal
- * executable lives. It is a fatal error if the
- * user-specified date file cannot be found.
- */
- n = 0;
- pathlist[n++] = "";
- if ((p = trnlog(PCAL_DIR)) != NULL)
- pathlist[n++] = p;
- pathlist[n++] = progpath;
- pathlist[n] = NULL;
-
- strcpy(tmp, datefile); /* save original name for error msg */
-
- if ((dfp = alt_fopen(datefile, tmp, pathlist, "r")) == NULL) {
- FPR(stderr, E_FOPEN_ERR, progname, tmp);
- exit(EXIT_FAILURE);
- }
- break;
-
- case SYS_DATEFILE:
- /* Attempt to open system-specified calendar file: search
- * first in PCAL_DIR, then in HOME_DIR (current directory
- * if neither is defined) and finally in the directory where
- * the Pcal executable lives. It is not an error if the
- * system-specified date file cannot be found; Pcal will
- * simply generate an empty calendar.
- */
- n = 0;
- if ((p = trnlog(PCAL_DIR)) != NULL)
- pathlist[n++] = p;
- if ((p = trnlog(HOME_DIR)) != NULL)
- pathlist[n++] = p;
- if (n == 0)
- pathlist[n++] = "";
- pathlist[n++] = progpath;
- pathlist[n] = NULL;
-
- dfp = alt_fopen(datefile, DATEFILE, pathlist, "r");
-
- /* if the date file has not been found and ALT_DATEFILE is
- * defined, search same paths for ALT_DATEFILE before
- * giving up
- */
- #ifdef ALT_DATEFILE
- if (!dfp)
- dfp = alt_fopen(datefile, ALT_DATEFILE, pathlist, "r");
- #endif
- break;
- }
-
- /* read the date file (if any) and build internal data structure */
-
- if (dfp) {
- curr_year = init_year;
- read_datefile(dfp, datefile);
- fclose(dfp);
- } else
- datefile[0] = '\0'; /* for PostScript comment */
-
- /* reparse command line - flags there supersede those in date file */
-
- (void) get_args(argv, P_CMD2, NULL, FALSE);
-
- /* if in whole-year mode, round number of months up to full year and
- * set default starting month to January of current year
- */
- if (do_whole_year) {
- nmonths = ((nmonths + 11) / 12) * 12;
- if (nargs == 0)
- init_month = JAN;
-
- /* also disable some meaningless flags */
- draw_moons = NO_MOONS;
- julian_dates = NO_JULIANS;
- }
-
- /* select an appropriate color for holidays if not set explicitly
- */
- if (holiday_color == HOLIDAY_DEFAULT)
- holiday_color = select_color();
-
- /* done with the arguments and flags - try to open the output file */
-
- if (*outfile && freopen(outfile, "w", stdout) == (FILE *) NULL) {
- FPR(stderr, E_FOPEN_ERR, progname, outfile);
- exit(EXIT_FAILURE);
- }
-
- /* generate the "calendar" or PostScript code (cf. writefil.c) */
-
- if (calendar_out)
- write_calfile(init_month, init_year, nmonths);
- else
- write_psfile(init_month, init_year, nmonths);
-
- cleanup(); /* free allocated data */
-
- /* if output was written to a non-obvious location, tell user where */
-
- #ifdef DEFAULT_OUTFILE
- FPR(stderr, I_OUT_NAME, progname, outfile);
- #endif
-
- exit(EXIT_SUCCESS);
- }
-
-
- /*
- * init_misc - various initializations not easily handled in .h files
- */
- void
- #ifdef PROTOS
- init_misc(void)
- #else
- init_misc()
- #endif
- {
- INIT_COLORS; /* copy default_color to day_color */
- strcpy(notes_hdr, default_notes_hdr); /* initialize notes_hdr */
- }
-
-
- /*
- * set_color - set one or all weekdays (or all holidays) to print in selected
- * color; also accept range such as mon-fri or sat-sun
- */
- void
- #ifdef PROTOS
- set_color(char *day, /* weekday name (or "all" or "holiday") */
- int col) /* select black/gray/outline/outline-gray */
- #else
- set_color(day, col)
- char *day; /* weekday name (or "all" or "holiday") */
- int col; /* select black/gray/outline/outline-gray */
- #endif
- {
- int i, j, max, count[NUM_COLORS];
- char tmp[STRSIZ], *p;
-
- if (ci_strncmp(day, ALL, strlen(ALL)) == 0) { /* set all days */
- for (i = 0; i < 7; i++)
- day_color[i] = col;
- }
-
- else if (ci_strncmp(day, HOLIDAY, MIN_DAY_LEN) == 0) /* set holidays */
- holiday_color = col;
-
- else { /* set range of days */
- strcpy(tmp, day);
- if ((p = strchr(tmp, '-')) != NULL)
- *p++ = '\0';
-
- /* parse single day or range of days - return if error */
- if ((i = get_weekday(tmp, FALSE)) == NOT_WEEKDAY ||
- (j = p ? get_weekday(p, FALSE) : i) == NOT_WEEKDAY)
- return;
-
- /* set day colors, wrapping around end of week */
- for (j = (i > j) ? j + 7 : j; i <= j; i++)
- day_color[i % 7] = col;
- }
-
- /* reset weekday_color to most prevalent color */
-
- for (i = 0; i < NUM_COLORS; i++) /* clear counts */
- count[i] = 0;
-
- for (i = SUN; i <= SAT; i++) /* count colors */
- count[day_color[i]]++;
-
- for (i = max = 0; i < NUM_COLORS; i++) /* get most prevalent */
- if (count[i] > max)
- max = count[weekday_color = i];
-
- }
-
-
- /*
- * change_color - reset existing non-black colors to selected color
- * (for backward-compatibility with pre-v4.4 -G and -O flags)
- */
- void
- #ifdef PROTOS
- change_color(int col)
- #else
- change_color(col)
- int col;
- #endif
- {
- int i;
-
- for (i = SUN; i <= SAT; i++)
- if (day_color[i] != BLACK)
- day_color[i] = col;
-
- if (holiday_color != BLACK && holiday_color != HOLIDAY_DEFAULT)
- holiday_color = col;
-
- }
-
-
- /*
- * get_flag() - look up flag in flag_tbl; return pointer to its entry
- * (NULL if not found)
- */
- FLAG_USAGE *
- #ifdef PROTOS
- get_flag(char flag)
- #else
- get_flag(flag)
- char flag;
- #endif
- {
- FLAG_USAGE *pflag;
-
- for (pflag = flag_tbl; pflag->flag; pflag++)
- if (flag == pflag->flag)
- return pflag;
-
- return flag ? NULL : pflag; /* '\0' is a valid flag */
- }
-
-
- /*
- * set_debug_flag - look up "flag" in debug flag table and set selected
- * bits in debug flag word (clear word if "flag" is NULL)
- */
- void
- #ifdef PROTOS
- set_debug_flag(char *flag)
- #else
- set_debug_flag(flag)
- char *flag;
- #endif
- {
- char f;
- DEBUG_INFO *pd;
-
- if (!flag) { /* clear all if NULL */
- debug_flags = 0;
- return;
- }
-
- /* loop through all characters in "flag", setting corresponding
- * bits in debug_flags
- */
- while (f = *flag++)
- for (pd = debug_info; pd->flag; pd++)
- if (pd->flag == f)
- debug_flags |= pd->value;
-
- }
-
- /*
- * get_args - walk the argument list, parsing all arguments but processing only
- * those specified (in flag_tbl[]) to be processed this pass; return TRUE if
- * OK, FALSE if invalid flag found.
- */
- int
- #ifdef PROTOS
- get_args(char **argv, /* argument list */
- int curr_pass, /* current pass (P_xxx) */
- char *where, /* for error messages */
- int get_numargs) /* parse and save numeric arguments? */
- #else
- get_args(argv, curr_pass, where, get_numargs)
- char **argv; /* argument list */
- int curr_pass; /* current pass (P_xxx) */
- char *where; /* for error messages */
- int get_numargs; /* parse and save numeric arguments? */
- #endif
- {
- char *parg, *opt, *p, *pass, tmpbuf[STRSIZ];
- FLAG_USAGE *pflag, *pf;
- int i, flag, sv_debug;
- int flags_ok = TRUE; /* return value */
- FILE *fp = stdout; /* for piping "help" message */
-
- /*
- * If argument follows flag (immediately or as next parameter), return
- * pointer to it (and bump argv if necessary); else return NULL
- */
- #define GETARG() (*(*argv + 2) ? *argv + 2 : \
- (*(argv+1) && **(argv+1) != '-' ? *++argv : NULL))
-
- /* set up pass name to print in debug messages */
-
- pass = where ? where :
- curr_pass == P_CMD0 ? "CMD0" :
- curr_pass == P_ENV ? "ENV" :
- curr_pass == P_CMD1 ? "CMD1" :
- curr_pass == P_CMD2 ? "CMD2" :
- "OPT" ;
-
- /* Walk argument list, ignoring first element (program name) */
-
- while (opt = *++argv) {
-
- /* Assume that any non-flag argument is a numeric argument */
- if (*opt != '-') {
- if (get_numargs && nargs < MAXARGS) {
- if (! IS_NUMERIC(opt))
- goto bad_par;
- numargs[nargs++] = atoi(opt);
- if (DEBUG(DEBUG_OPTS))
- FPR(stderr, "%s: %s\n", pass, opt);
- }
- continue;
- }
-
- /* Check that flag is a) legal, and b) to be processed this pass */
-
- if (! (pflag = get_flag(flag = opt[1])) )
- goto bad_par;
-
- /* get optional argument even if flag not processed this pass */
-
- parg = pflag->has_arg ? GETARG() : NULL;
-
- if (! (pflag->passes & curr_pass)) { /* skip flag this pass? */
- if (curr_pass == P_OPT)
- FPR(stderr, E_FLAG_IGNORED, progname, flag,
- DATE_FILE, where);
- continue;
- }
-
- /* echo pass name and flag if debugging on */
- if (DEBUG(DEBUG_OPTS))
- FPR(stderr, "%s: -%c%s%s\n", pass, flag,
- parg ? " " : "", parg ? parg : "");
-
- /* convert escape sequences in command-line parameters */
- if (parg && (curr_pass == P_CMD1 || curr_pass == P_CMD2)) {
- cvt_escape(tmpbuf, parg);
- parg = tmpbuf;
- }
-
- switch (flag) {
-
- case F_INITIALIZE: /* reset all flags to defaults */
-
- /* set up a command line to reset all of the
- * flags; call get_args() recursively to parse it
- * (note that some of the flags must be reset
- * explicitly, as no command-line flags exist to
- * reset them)
- */
-
- /* reset flags described above */
- julian_dates = JULIAN_DATES;
- draw_moons = DRAW_MOONS;
- do_whole_year = DO_WHOLE_YEAR;
- blank_boxes = BLANK_BOXES;
- calendar_out = CALENDAR_OUT;
- small_cal_pos = SMALL_CAL_POS;
-
- /* select program default for landscape/portrait
- * mode (must be done first because -[xXyY] depend
- * on it) and US/European date styles
- */
- sprintf(lbuf, "pcal -%c -%c",
- #if (ROTATE == LANDSCAPE)
- F_LANDSCAPE,
- #else
- F_PORTRAIT,
- #endif
- #if (DATE_STYLE == USA_DATES)
- F_USA_DATES);
- #else
- F_EUR_DATES);
- #endif
- p = lbuf + strlen(lbuf);
-
- /* all other flags take arguments and are reset
- * by specifying the flag without an argument
- */
- for (pf = flag_tbl; pf->flag; pf++)
- if ((pf->passes & curr_pass) && pf->has_arg) {
- sprintf(p, " -%c", pf->flag);
- p += strlen(p);
- }
-
- /* split new command line into words; parse it */
- (void) loadwords(words, lbuf);
- (void) get_args(words, curr_pass, NULL, FALSE);
-
- /* -G and -O without arguments change some day
- * colors (for backward-compatibility with
- * pre-v4.4 versions), so initialize the day
- * colors explicitly
- */
- INIT_COLORS;
-
- /* also disable the time zone flag explicitly */
- tz_flag = FALSE;
-
- break;
-
- case F_BLACK_DAY: /* print day in black or gray */
- case F_GRAY_DAY:
- if (parg)
- set_color(parg, flag == F_BLACK_DAY ?
- BLACK : GRAY);
- else
- INIT_COLORS; /* reset to defaults */
- break;
-
- case F_OUTLINE: /* print day in outline or outline-gray */
- case F_OUTLINE_GRAY:
- /* ignore "-Gall" etc. on second command-line pass;
- * this is to avoid changing the definition of
- * "weekday", et. al. after the date file has already
- * been read
- */
- if (parg) {
- if (curr_pass != P_CMD2)
- set_color(parg, flag == F_OUTLINE ?
- OUTLINE :
- OUTLINE_GRAY);
- }
- else
- /* special hack for backward compatibility
- * with v4.3 and earlier: -G or -O alone
- * change all non-black days to the selected
- * color
- */
- change_color(flag == F_OUTLINE ?
- OUTLINE : OUTLINE_GRAY);
-
- break;
-
- case F_DAY_FONT: /* specify alternate day font */
- define_font(datefont, parg, DATEFONT);
- break;
-
- case F_NOTES_FONT: /* specify alternate notes font */
- define_font(notesfont, parg, NOTESFONT);
- break;
-
- case F_TITLE_FONT: /* specify alternate title font */
- define_font(titlefont, parg, TITLEFONT);
- break;
-
- case F_REMAP_FONT: /* specify 8-bit font mapping */
- if (parg) {
- if (ci_strncmp(parg, MAPPING_R, 1) == 0)
- mapfonts = ROMAN8;
- else if (ci_strncmp(parg, MAPPING_L, 1) == 0)
- mapfonts = LATIN1;
- else
- mapfonts = NOMAP;
- } else
- mapfonts = MAPFONTS;
- break;
-
- case F_EMPTY_CAL: /* generate empty calendar */
- datefile_type = NO_DATEFILE;
- strcpy(datefile, "");
- break;
-
- case F_DATE_FILE: /* specify alternate date file */
- datefile_type = parg ? USER_DATEFILE : SYS_DATEFILE;
- strcpy(datefile, parg ? parg : "");
- break;
-
- case F_OUT_FILE: /* specify alternate output file */
- strcpy(outfile, parg ? parg : OUTFILE);
- break;
-
- case F_LANDSCAPE: /* generate landscape calendar */
- rotate = LANDSCAPE;
- strcpy(xsval, XSVAL_L);
- strcpy(ysval, YSVAL_L);
- strcpy(xtval, XTVAL_L);
- strcpy(ytval, YTVAL_L);
- break;
-
- case F_PORTRAIT: /* generate portrait calendar */
- rotate = PORTRAIT;
- strcpy(xsval, XSVAL_P);
- strcpy(ysval, YSVAL_P);
- strcpy(xtval, XTVAL_P);
- strcpy(ytval, YTVAL_P);
- break;
-
- case F_HELP: /* request version info and/or help */
- case F_USAGE:
- case F_VERSION:
- /* PAGER_ENV (cf. pcaldefs.h) defines the name of an
- * environment variable which, if set, points to the
- * appropriate pager (e.g., "more", "less", "pg")
- * for piping the "help" message (Un*x systems only)
- */
- #ifdef PAGER_ENV
- if (flag == F_HELP) {
- FILE *pfp;
- char *pager, *p;
-
- pager = (p = getenv(PAGER_ENV)) ? p :
- PAGER_DEFAULT;
- /* null pointer or string: no paging */
- if (pager && *pager &&
- (pfp = popen(pager, "w")) != (FILE *)NULL)
- fp = pfp;
- }
- #endif
- FPR(fp, "%s\n", VERSION_STRING + 4);
- if (flag != F_VERSION)
- usage(fp, flag == F_HELP);
- fflush(fp);
- #ifdef PAGER_ENV
- if (fp != stdout)
- pclose(fp);
- #endif
- exit(EXIT_SUCCESS);
- break;
-
- case F_MOON_4: /* draw four moons */
- case F_MOON_ALL: /* draw a moon for each day */
- draw_moons = flag == F_MOON_ALL ? ALL_MOONS : SOME_MOONS;
- break;
-
- case F_DEFINE: /* define preprocessor symbol */
- (void) do_define(parg);
- break;
-
- case F_UNDEF: /* undef preprocessor symbol */
- (void) do_undef(parg);
- break;
-
- case F_L_FOOT: /* specify alternate left foot */
- strcpy(lfoot, parg ? parg : LFOOT);
- break;
-
- case F_C_FOOT: /* specify alternate center foot */
- strcpy(cfoot, parg ? parg : CFOOT);
- break;
-
- case F_R_FOOT: /* specify alternate right foot */
- strcpy(rfoot, parg ? parg : RFOOT);
- break;
-
- case F_NOTES_HDR: /* specify alternate notes header */
- strcpy(notes_hdr, parg ? parg : default_notes_hdr);
- break;
-
- case F_FIRST_DAY: /* select starting day of week */
- if (parg) {
- if ((i = get_weekday(parg, FALSE)) != NOT_WEEKDAY)
- first_day_of_week = i;
- }
- else
- first_day_of_week = FIRST_DAY;
- break;
-
- case F_USA_DATES: /* select American date style */
- case F_EUR_DATES: /* select European date style */
- date_style = flag == F_USA_DATES ? USA_DATES : EUR_DATES;
- break;
-
- case F_X_TRANS: /* set x-axis translation factor */
- strcpy(xtval, parg ? parg :
- (rotate == LANDSCAPE ? XTVAL_L : XTVAL_P));
- break;
-
- case F_Y_TRANS: /* set y-axis translation factor */
- strcpy(ytval, parg ? parg :
- (rotate == LANDSCAPE ? YTVAL_L : YTVAL_P));
- break;
-
- case F_X_SCALE: /* set x-axis scaling factor */
- strcpy(xsval, parg ? parg :
- (rotate == LANDSCAPE ? XSVAL_L : XSVAL_P));
- break;
-
- case F_Y_SCALE: /* set y-axis scaling factor */
- strcpy(ysval, parg ? parg :
- (rotate == LANDSCAPE ? YSVAL_L : YSVAL_P));
- break;
-
- case F_JULIAN: /* display Julian dates */
- case F_JULIAN_ALL: /* Julian date/days remaining */
- julian_dates = flag == F_JULIAN_ALL ? ALL_JULIANS :
- SOME_JULIANS;
- break;
-
- case F_WHOLE_YEAR: /* print whole year at once */
- do_whole_year = !(DO_WHOLE_YEAR);
- (void) do_define(DEF_WHOLE_YEAR);
- break;
-
- case F_CALENDAR: /* generate "calendar(1)" input */
- calendar_out = !(CALENDAR_OUT);
- break;
-
- case F_BLANK_BOXES: /* suppress shading unused boxes */
- blank_boxes = !(BLANK_BOXES);
- break;
-
- case F_NUM_PAGES: /* print multiple copies of each page */
- strcpy(ncopy, parg ? parg : NCOPY);
- break;
-
- case F_SC_NONE: /* suppress small calendars */
- small_cal_pos = SC_NONE;
- break;
-
- case F_SC_FIRST: /* reposition of small calendars */
- case F_SC_SPLIT:
- small_cal_pos = flag == F_SC_FIRST ? SC_FIRST :
- SC_SPLIT;
- break;
-
- case F_SHADING: /* set date/fill shading levels */
- define_shading(shading, parg, SHADING);
- break;
-
- case F_TIMEZONE: /* select alternate time zone */
- strcpy(time_zone, parg ? parg : TIMEZONE);
- tz_flag = TRUE;
- break;
-
- case F_DEBUG: /* turn on debugging (undocumented) */
- sv_debug = DEBUG(DEBUG_OPTS);
- set_debug_flag(parg);
-
- /* print -ZO flag if first time set */
- if (!sv_debug && DEBUG(DEBUG_OPTS))
- FPR(stderr, "%s: -%c%s\n", pass, flag,
- parg ? parg : "");
- break;
-
- case '-' : /* accept - and -- as dummy flags */
- case '\0':
- break;
-
- default: /* missing case label if reached!!! */
-
- bad_par: /* unrecognized parameter */
-
- FPR(stderr, E_ILL_OPT, progname, opt);
- if (where)
- FPR(stderr, E_ILL_OPT2,
- curr_pass == P_ENV ? ENV_VAR :
- curr_pass == P_OPT ? DATE_FILE : "",
- where);
- FPR(stderr, "\n");
- flags_ok = FALSE;
- break;
- }
- }
-
- /* if we read the numeric arguments, validate and interpret them */
- if (get_numargs)
- flags_ok &= check_numargs();
-
- return flags_ok;
- }
-
-
- /*
- * check_numargs - validate and interpret numeric command-line parameters;
- * return TRUE if all OK, print error message and return FALSE if not
- */
- int
- #ifdef PROTOS
- check_numargs(void)
- #else
- check_numargs()
- #endif
- {
- /* Validate non-flag (numeric) parameters */
-
- struct tm *p_tm; /* for getting current month/year */
- time_t tmp;
- int params_ok = TRUE; /* return value */
-
- switch (nargs) {
- case 0: /* no arguments - print current month and/or year */
- time(&tmp);
- p_tm = localtime(&tmp);
- init_month = p_tm->tm_mon + 1;
- init_year = p_tm->tm_year;
- nmonths = 1;
- break;
-
- case 1: /* one argument - print entire year */
- init_month = JAN;
- init_year = numargs[0];
- nmonths = 12;
- break;
-
- default: /* two or three arguments - print one or more months */
- init_month = numargs[0];
- init_year = numargs[1];
- nmonths = nargs > 2 ? numargs[2] : 1;
- break;
- }
-
- if (nmonths < 1) /* ensure at least one month */
- nmonths = 1;
-
- /* check range of month and year */
-
- if (init_month < JAN || init_month > DEC) {
- FPR(stderr, E_ILL_MONTH, progname, init_month, JAN, DEC);
- params_ok = FALSE;
- }
-
- if (init_year > 0 && init_year < 100) /* treat nn as 19nn */
- init_year += CENTURY;
-
- if (init_year < MIN_YR || init_year > MAX_YR) {
- FPR(stderr, E_ILL_YEAR, progname, init_year, MIN_YR, MAX_YR);
- params_ok = FALSE;
- }
-
- return params_ok;
- }
-
-
-
- /*
- * color_msg - return character string explaining default day colors;
- * assumes that defaults consist of black and at most one other color
- */
- char *
- #ifdef PROTOS
- color_msg(void)
- #else
- color_msg()
- #endif
- {
- int i, ngray = 0, others, gray;
- static char msg[80], *alt_color;
-
- for (i = SUN; i <= SAT; i++) /* count "logical gray" weekdays */
- if (default_color[i] != BLACK) {
- gray = default_color[i];
- ngray++;
- }
-
- alt_color = color_names[gray]; /* map "logical gray" to its name */
-
- if (ngray == 0 || ngray == 7) { /* all same color? */
- sprintf(msg, COLOR_MSG_1, ngray ? alt_color : W_BLACK);
- return msg;
- }
-
- others = ngray <= 3 ? BLACK : gray; /* no - get predominant color */
- msg[0] = '\0';
- for (i = SUN; i <= SAT; i++)
- if (default_color[i] != others) {
- strncat(msg, days[i], MIN_DAY_LEN);
- strcat(msg, "/");
- }
- LASTCHAR(msg) = ' ';
-
- sprintf(msg + strlen(msg), COLOR_MSG_2,
- others == BLACK ? alt_color : W_BLACK,
- others == BLACK ? W_BLACK : alt_color);
- return msg;
- }
-
-
- /*
- * usage - print message explaining correct usage of the command-line
- * arguments and flags. If "fullmsg" is true, print associated text
- */
- void
- #ifdef PROTOS
- usage(FILE *fp, /* destination of usage message */
- int fullmsg) /* print complete message? */
- #else
- usage(fp, fullmsg)
- FILE *fp; /* destination of usage message */
- int fullmsg; /* print complete message? */
- #endif
- {
- FLAG_MSG *pflag;
- PARAM_MSG *ppar;
- DATE_MSG *pdate;
- KWD_H *phol;
- char buf[30], *p, flag, *meta;
- int nchars, first, i, indent, n;
-
- sprintf(buf, "%s: %s", W_USAGE, progname);
- nchars = indent = strlen(buf);
- first = TRUE;
- meta = p = NULL;
- FPR(fp, "\n%s", buf);
-
- /* loop to print command-line syntax message (by group of flags) */
-
- for (pflag = flag_msg; (flag = pflag->flag) != '\0'; pflag++) {
- if (flag == '\n') { /* end of group? */
- if (p)
- *p = '\0';
- if (meta) { /* append metavariable name */
- strcat(buf, " ");
- strcat(buf, meta);
- }
- strcat(buf, "]");
- n = strlen(buf);
- if (nchars + n > SCREENWIDTH) { /* does it fit on line? */
- FPR(fp, "\n"); /* no - start new one */
- for (nchars = 0; nchars < indent; nchars++)
- FPR(fp, " ");
- }
- FPR(fp, "%s", buf);
- nchars += n;
- first = TRUE;
- }
- else if (flag != ' ') { /* accumulate flags for group */
- if (first) {
- sprintf(buf, " [");
- p = buf + strlen(buf);
- }
- else
- *p++ = '|';
- *p++ = '-';
- *p++ = flag;
- meta = pflag->meta; /* save metavariable name */
- first = FALSE;
- }
- }
-
- /* loop to print selected numeric parameter descriptions */
-
- for (i = 0; i < PARAM_MSGS; i++) {
- sprintf(buf, " [%s]%s", param_msg[i].desc,
- i < PARAM_MSGS - 1 ? " |" : "");
- n = strlen(buf);
- if (nchars + n > SCREENWIDTH) { /* does it fit on line? */
- FPR(fp, "\n"); /* no - start new one */
- for (nchars = 0; nchars < indent; nchars++)
- FPR(fp, " ");
- }
- FPR(fp, "%s", buf);
- nchars += n;
- }
-
- FPR(fp, "\n\n");
- if (! fullmsg) {
- FPR(fp, USAGE_MSG, progname, F_HELP);
- return;
- }
-
- /* loop to print the full flag descriptions */
-
- for (pflag = flag_msg; (flag = pflag->flag) != '\0'; pflag++) {
- if (flag == '\n') { /* newline? print and quit */
- FPR(fp, "\n");
- continue;
- }
- p = buf; /* copy flag and metavariable to buffer */
- if (flag != ' ')
- *p++ = '-';
- /* special hack for VMS - surround upper-case flags in quotes */
- #ifdef VMS
- if (isupper(flag)) {
- *p++ = '"';
- *p++ = flag;
- *p++ = '"';
- }
- else
- *p++ = flag;
- #else
- *p++ = flag;
- #endif
- *p = '\0';
- if (pflag->meta)
- sprintf(p, " %s", pflag->meta);
- FPR(fp, "\t%-20.20s", buf);
- if (pflag->text)
- FPR(fp, "%s", pflag->text);
-
- /* print default value if specified */
- if (pflag->def)
- FPR(fp, " (%s: %s)", W_DEFAULT, pflag->def[0] ? pflag->def : "\"\"" );
- FPR(fp, "\n");
-
- /* special case - print color messages after F_OUTLINE_GRAY */
- if (flag == F_OUTLINE_GRAY)
- FPR(fp, "\t%20s (%s: %s)\n", "", W_DEFAULT, color_msg());
-
- }
-
- /* now print the information about the numeric parameters */
-
- for (ppar = param_msg; ppar->desc; ppar++)
- FPR(fp, "\t%-16.16s%s\n", ppar->desc, ppar->text);
-
- /* print the date file syntax message */
-
- FPR(fp, "\n");
- for (pdate = date_msg; *pdate; pdate++)
- FPR(fp, "\t%s\n", *pdate);
-
- /* print list of predefined holidays */
- FPR(fp, "\n\t%s\n\n", PREDEF_MSG_1);
- #define N 4
- for (phol = holidays, n = 0; phol->name; phol++, n = (n + 1) % N)
- FPR(fp, "%s%-15.15s %s", n == 0 ? "\t " : "", phol->name,
- (n == N - 1) || !(phol[1].name) ? "\n" : "");
- FPR(fp, "\n\t%s\n", PREDEF_MSG_2);
- FPR(fp, "\n");
-
- }
-
-
- /*
- * alt_fopen - attempt to open a file in one of several paths in a
- * NULL-terminated path list. If successful, return (opened) file pointer
- * and fill in full path name; if not, return NULL
- */
- FILE *
- #ifdef PROTOS
- alt_fopen(char *fullpath, /* full path name (output) */
- char *name, /* base name (or full path spec) */
- char *pathlist[], /* NULL-terminated path list */
- char *access) /* permission requested */
- #else
- alt_fopen(fullpath, name, pathlist, access)
- char *fullpath; /* full path name (output) */
- char *name; /* base name (or full path spec) */
- char *pathlist[]; /* NULL-terminated path list */
- char *access; /* permission requested */
- #endif
- {
- char **path;
- FILE *fp;
-
- if (DEBUG(DEBUG_PATHS)) {
- FPR(stderr, "Searching for %s in the following paths:\n",
- name);
- for (path = pathlist; *path; path++)
- FPR(stderr, " %s\n", **path ? *path : ".");
- }
-
- for (path = pathlist; *path; path++) {
- mk_filespec(fullpath, *path, name);
- if ((fp = fopen(fullpath, access)) != NULL) {
- if (DEBUG(DEBUG_PATHS))
- FPR(stderr, "found %s\n", fullpath);
- return fp;
- }
- }
-
- fullpath[0] = '\0'; /* file not found */
- return NULL;
- }
-